#include <iostream>
#include <vector>
#include "../CImg/CImg.h"
using namespace std;
using namespace cimg_library;

class LUTWindow: public CImgDisplay{
	private:
	int x0, y0, x1, y1; // coordenadas de los ptos
	int dragging; // 0 si no hay dragging, 1 o 2 segun el pto que estamos arrastrando
	CImg<unsigned char> grafico; // el grafico
	static const float pointSize_2=5.0; // el radio de los ptos para dibujar y detectar click
	
	
	public:
	LUTWindow(){
		// inicializamos cosas
		dragging=0;
		x0=30; y0=225;
		x1=225; y1=30;
		// creamos un grafico de 256x256
		grafico.assign(256, 256, 1, 3);
		assign(grafico);
		set_title("LUT Window");
		dibujar(); // para que se refresque apenas aparece
	}
	
	// repinta la ventana del grafico
	void dibujar(){
		unsigned char rojo[]={255, 0, 0};
		unsigned char blue[]={0, 0, 255};
		grafico.fill(255);
		
		grafico.draw_line(x0, y0, x1, y1, blue);
		grafico.draw_line(0, 255, x0, y0, blue);
		grafico.draw_line(x1, y1, 255, 0, blue);
		
		grafico.draw_circle(x0, y0, pointSize_2, rojo);
		grafico.draw_circle(x1, y1, pointSize_2, rojo);
		
		render(grafico);
		paint();
	}
	
	// maneja los eventos
	void manejarEventos(){
		// si hay click y no estaba arrastrando buscamos si el click fue cerca de alguno de los 2 ptos
		if(button()!=0 && !dragging){
			if(sqrt(powf(x0-mouse_x(),2)+powf(y0-mouse_y(),2))<=pointSize_2){
				dragging=1;
			}else if(sqrt(powf(x1-mouse_x(),2)+powf(y1-mouse_y(),2))<=pointSize_2){
				dragging=2;
			}
		// si se solto el boton y estabamos arrastrando desactivamos el arrastre
		}else if(!button() && dragging){
			dragging=0;
		// si arrastramos el 1er pto
		}else if(dragging==1){
			// hacemos algunas comprobaciones
			if((mouse_x()>0 && mouse_x()<255) && (mouse_y()>0 && mouse_y()<255) && mouse_x()<x1 && mouse_y()>y1){ // en la ultima condicion los y estan al reves
				x0=mouse_x();
				y0=mouse_y();
				dibujar();
			}
		}else if(dragging==2){
			// hacemos algunas comprobaciones
			if((mouse_x()>0 && mouse_x()<255) && (mouse_y()>0 && mouse_y()<255) && mouse_x()>x0 && mouse_y()<y0){ // en la ultima condicion los y estan al reves
				x1=mouse_x();
				y1=mouse_y();
				dibujar();
			}
		}
	}
		
	// calcula y devuelve un vector con los valores de la LUT segun la ventana
	vector<unsigned char> GetLUT(){
		vector<unsigned char> LUT(256);
		unsigned y0, y1;
		y0=255-this->y0;
		y1=255-this->y1;
		
		for(unsigned i=0; i<256; i++){
			if(i<x0){
				LUT[i]=(float(y0)/x0)*i; // pendiente de la 1er recta
			}else if(i>=x0 && i<x1){
				LUT[i]=(float(y1-y0)/(x1-x0))*(i-x0)+y0; // ojo que el i debe ser a partir de x0
			}else{
				LUT[i]=(float(255-y1)/(255-x1))*(i-x1)+y1;
			}
		}
		return LUT;
	}
	
};



CImg<unsigned char> ApplyLUT(CImg<unsigned char> img, vector<unsigned char> LUT){
	CImg<unsigned char> salida(img.width(), img.height());
	// aplicamos la LUT
	for(unsigned i=0; i<img.width(); i++){
		for(unsigned j=0; j<img.height(); j++){
			salida(i, j)=LUT[img(i, j)];
		}
		
	}
	return salida;
}





int main(int argc, char *argv[]) {
	CImg<unsigned char> img, imgLUT; 
	CImgDisplay displayImagen;
	
	img.load("../img_test/earth.bmp");
	imgLUT=img;
	displayImagen.assign(imgLUT);
	
	LUTWindow w;
	vector<unsigned char> LUT;
	
	while(!w.is_closed() && !displayImagen.is_closed()){
		w.wait_all();
		w.manejarEventos();
		w.dibujar();
		LUT=w.GetLUT();
		imgLUT=ApplyLUT(img, LUT);
		displayImagen.render(imgLUT);
		displayImagen.paint();
	}
	
	return 0;
}


